package com.zzyl.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zzyl.service.WechatService;
import com.zzyl.utils.ObjectUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class WechatServiceImpl implements WechatService {

    // 登录
    private static final String REQUEST_URL = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code";

    // 获取token
    private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";

    // 获取手机号
    private static final String PHONE_REQUEST_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";

    @Value("${zzyl.wechat.appId}")
    private String appId;

    @Value("${zzyl.wechat.appSecret}")
    private String secret;

    /**
     * 获取openid
     * @param code：userLoginRequestDto.getCode()  登录凭证
     *        userLoginRequestDto：用户登录信息，包含微信登录所需的code和phoneCode
     * @return
     * 调用 auth.code2Session 接口，换取 用户唯一标识 OpenID 、 用户在微信开放平台账号下的唯一标识UnionID（若当前小程序已绑定到微信开放平台账号）
     * 和 会话密钥 session_key。
     */
    /**
     * 接口说明：code2Session
     * GET <a href="https://api.weixin.qq.com/sns/jscode2session">...</a>
     * 请求参数：
     * 属性	        类型	       必填	  说明
     * appid	    string	   是	  小程序 appId
     * secret	    string	   是	  小程序 appSecret
     * js_code	    string	   是	  登录时获取的 code，可通过wx.login获取
     * grant_type	string	   是	  授权类型，此处只需填写 authorization_code
     * 返回参数：
     * 属性	           类型	        说明
     * session_key	   string	    会话密钥
     * unionid	       string	    用户在开放平台的唯一标识符，若当前小程序已绑定到微信开放平台帐号下会返回，详见 UnionID 机制说明。
     * errmsg	       string	    错误信息，请求失败时返回
     * openid	       string	    用户唯一标识
     * errcode	       int32	    错误码，请求失败时返回
     */
    @Override
    public String getOpenid(String code) {
        Map<String, Object> requestUrlParam = getAppConfig(); // getAppConfig() = appId + secret
        requestUrlParam.put("js_code", code);
        System.out.println("requestUrlParam=" + requestUrlParam);
        String result = HttpUtil.get(REQUEST_URL, requestUrlParam);
        //反序列化
        JSONObject jsonObject = JSONUtil.parseObj(result);
        // 若code不正确，则获取不到openid，响应失败
        if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
            throw new RuntimeException(jsonObject.getStr("errmsg"));
        }
        System.out.println("jsonObject=" + jsonObject);
        return jsonObject.getStr("openid");
    }

    /**
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html">...</a>
     * 获取手机号
     *
     * @param code 手机号凭证
     * @return
     */
    @Override
    public String getPhone(String code) {
        //获取access_token
        String token = getToken();
        //拼接请求路径
        String url = PHONE_REQUEST_URL + token;
        Map<String, Object> param = new HashMap<>();
        param.put("code", code);
        String result = HttpUtil.post(url, JSONUtil.toJsonStr(param));
        JSONObject jsonObject = JSONUtil.parseObj(result);
        if (jsonObject.getInt("errcode") != 0) {
            //若code不正确，则获取不到phone，响应失败
            throw new RuntimeException(jsonObject.getStr("errmsg"));
        }
        System.out.println(jsonObject);
        return jsonObject.getJSONObject("phone_info").getStr("purePhoneNumber");
    }

    /**
     * <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html">...</a>
     * 获取小程序全局唯一后台接口调用凭据，token有效期为7200s，开发者需要进行妥善保存
     * 微信平台的 Token
     * 用途：调用微信API的凭证
     * 获取方式：<a href="https://api.weixin.qq.com/cgi-bin/token">...</a>
     * 包含信息：access_token，有效期2小时
     * 使用场景：服务器调用微信各种接口
     * 请求参数
     * 属性	        类型	    必填	    说明
     * grant_type	string	是	    填写 client_credential
     * appid	    string	是	    小程序唯一凭证，即 AppID，可在「微信公众平台 - 设置 - 开发设置」页中获得。（需要已经成为开发者，且帐号没有异常状态）
     * secret	    string	是	    小程序唯一凭证密钥，即 AppSecret，获取方式同 appid
     * 返回参数
     * 属性	            类型	    说明
     * access_token	string	获取到的凭证
     * expires_in	    number	凭证有效时间，单位：秒。目前是7200秒之内的值。
     */
    private String getToken() {
        Map<String, Object> requestUrlParam = getAppConfig();
        String result = HttpUtil.get(TOKEN_URL, requestUrlParam);
        //解析
        JSONObject jsonObject = JSONUtil.parseObj(result);
        //如果code不正确，则失败
        if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
            throw new RuntimeException(jsonObject.getStr("errmsg"));
        }
        System.out.println(jsonObject);
        return jsonObject.getStr("access_token");
    }

    /**
     * 封装公共参数
     *
     * @return
     */
    private Map<String, Object> getAppConfig() {

        Map<String, Object> requestUrlParam = new HashMap<>();
        requestUrlParam.put("appid", appId);
        requestUrlParam.put("secret", secret);
        return requestUrlParam;
    }
}
